home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
tcl
/
tclm_1_0.lha
/
tclm-1.0
/
tclmPlay.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-16
|
17KB
|
714 lines
/*-
* Copyright (c) 1993 Michael B. Durian. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Michael B. Durian.
* 4. The name of the the Author may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* tclmPlay.c,v 1.9 1993/05/07 17:45:11 durian Exp
*/
#ifdef MIDIPLAY
static char cvsid[] = "tclmPlay.c,v 1.9 1993/05/07 17:45:11 durian Exp";
#include <signal.h>
#include <sys/ioctl.h>
#include <i386/isa/midiioctl.h>
#include "tclInt.h"
#include "tclUnix.h"
#include "mutil.h"
#include "mdevice.h"
#include "tclm.h"
#include "tclmPlay.h"
static int now_playing = 0;
static int Dev;
static PlayMode Mode;
static int Pipe[2];
static char *play_usage = "midiplay [bg | background] [repeat] \
[tracks track_list] [reltempo tempo_scalar] mfileId";
static char *record_usage = "midirecord [bg | background] [play play_mfileId \
[repeat] [tracks track_list] [reltempo tempo_scalar]] record_mfileId";
void
Tclm_InitPlay(interp)
Tcl_Interp *interp;
{
Tcl_CreateCommand(interp, "midiplay", Tclm_MidiPlay, NULL, NULL);
Tcl_CreateCommand(interp, "midirecord", Tclm_MidiRecord, NULL, NULL);
Tcl_CreateCommand(interp, "midistop", Tclm_MidiStop, NULL, NULL);
signal(SIGCHLD, watchdog);
signal(SIGHUP, Tclm_CatchStop);
}
int
Tclm_MidiPlay(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
double reltempo;
MIDI_FILE *mfile;
char *mfile_name;
int *tracks;
int background;
int i;
int num_tracks;
int pid;
int repeat;
int result;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
play_usage, "\"", (char *)NULL);
return (TCL_ERROR);
}
reltempo = 1.0;
repeat = 0;
background = 0;
mfile_name = NULL;
tracks = NULL;
num_tracks = 0;
for (i = 1; i < argc; i++) {
switch(argv[i][0]) {
case 'b':
if (strncmp(argv[i], "bg", sizeof(argv[i])) == 0 ||
strncmp(argv[i], "background", sizeof(argv[i]))
== 0)
background = 1;
else if (mfile_name == NULL)
mfile_name = argv[i];
else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", play_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
break;
case 'r':
if (strncmp(argv[i], "reltempo", strlen(argv[i]))
== 0)
reltempo = atof(argv[++i]);
else if (strncmp(argv[i], "repeat", strlen(argv[i]))
== 0)
repeat = 1;
else if (mfile_name == NULL)
mfile_name = argv[i];
else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", play_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
break;
case 't':
if (strncmp(argv[i], "tracks", strlen(argv[i]))
== 0) {
if ((num_tracks = Tclm_ParseTracks(interp,
argv[i + 1], &tracks)) == -1)
return (TCL_ERROR);
i++;
} else if (mfile_name == NULL) {
mfile_name = argv[i];
} else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", play_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
break;
default:
if (mfile_name == NULL)
mfile_name = argv[i];
else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", play_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
}
}
if ((result = Tclm_GetMFile(interp, mfile_name, &mfile)) != TCL_OK) {
if (tracks != NULL)
free(tracks);
return (result);
}
/* If track list isn't set use all tracks */
if (num_tracks == 0) {
num_tracks = mfile->hchunk.num_trks;
if ((tracks = (int *)malloc(sizeof(int) * num_tracks))
== NULL) {
Tcl_AppendResult(interp, "Not enough memory",
(char *)NULL);
return (TCL_ERROR);
}
for (i = 0; i < num_tracks; i++)
tracks[i] = i;
}
Mode = PLAY;
if ((Dev = open_midi_device(Mode)) == -1) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
free(tracks);
return (TCL_ERROR);
}
if (!init_midi_device(Dev, &mfile->hchunk, reltempo)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
free(tracks);
return (TCL_ERROR);
}
if (!start_midi_device(Dev, Mode)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
free(tracks);
return (TCL_ERROR);
}
if (!background) {
now_playing = 1;
if (!play_tracks(Dev, mfile->tchunks, tracks, num_tracks,
repeat)) {
Tcl_AppendResult(interp, "Couldn't play tracks\n",
MidiError, (char *)NULL);
free(tracks);
return (TCL_ERROR);
}
now_playing = 0;
if (!stop_midi_device(Dev, Mode)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
free(tracks);
return (TCL_ERROR);
}
/*
* give time for the stop to take effect
* since stop might not happen until next clock
*/
sleep(1);
if (!close_midi_device(Dev)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
free(tracks);
return (TCL_ERROR);
}
Tcl_AppendResult(interp, "0", (char *)NULL);
} else {
switch(pid = fork()) {
case -1:
Tcl_AppendResult(interp, "Couldn't fork",
(char *)NULL);
free(tracks);
return (TCL_ERROR);
case 0:
/* child */
now_playing = 1;
if (!play_tracks(Dev, mfile->tchunks, tracks,
num_tracks, repeat)) {
Tcl_AppendResult(interp,
"Couldn't play tracks\n", MidiError,
(char *)NULL);
free(tracks);
return (TCL_ERROR);
}
now_playing = 0;
if (!stop_midi_device(Dev, Mode)) {
Tcl_AppendResult(interp, MidiError,
(char *)NULL);
free(tracks);
return (TCL_ERROR);
}
/*
* give time for the stop to take effect
* since stop might not happen until next clock
*/
sleep(1);
if (!close_midi_device(Dev)) {
Tcl_AppendResult(interp, MidiError,
(char *)NULL);
free(tracks);
return (TCL_ERROR);
}
exit(0);
default:
if (!close_midi_device(Dev)) {
Tcl_AppendResult(interp, MidiError,
(char *)NULL);
free(tracks);
return (TCL_ERROR);
}
sprintf(interp->result, "%d", pid);
break;
}
}
free(tracks);
return (TCL_OK);
}
int
Tclm_MidiRecord(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
double reltempo;
MIDI_FILE *pfile;
MIDI_FILE *rfile;
TCHUNK *play_tracks;
TCHUNK *tmp_track;
char *pfile_name;
char *rfile_name;
int *tracks;
int background;
int i;
int num_tracks;
int pid;
int repeat;
int result;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
record_usage, "\"", (char *)NULL);
return (TCL_ERROR);
}
reltempo = 1.0;
repeat = 0;
background = 0;
pfile = NULL;
rfile = NULL;
pfile_name = NULL;
rfile_name = NULL;
tracks = NULL;
num_tracks = 0;
for (i = 1; i < argc; i++) {
switch(argv[i][0]) {
case 'b':
if (strncmp(argv[i], "bg", sizeof(argv[i])) == 0 ||
strncmp(argv[i], "background", sizeof(argv[i]))
== 0)
background = 1;
else if (rfile_name == NULL)
rfile_name = argv[i];
else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", record_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
break;
case 'p':
if (strncmp(argv[i], "play", sizeof(argv[i])) == 0)
pfile_name = argv[++i];
else if (rfile_name == NULL)
rfile_name = argv[i];
else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", record_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
break;
case 'r':
if (strncmp(argv[i], "reltempo", strlen(argv[i]))
== 0)
reltempo = atof(argv[++i]);
else if (strncmp(argv[i], "repeat", strlen(argv[i]))
== 0)
repeat = 1;
else if (rfile_name == NULL)
rfile_name = argv[i];
else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", record_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
break;
case 't':
if (strncmp(argv[i], "tracks", strlen(argv[i]))
== 0) {
if ((num_tracks = Tclm_ParseTracks(interp,
argv[i + 1], &tracks)) == -1)
return (TCL_ERROR);
i++;
} else if (rfile_name == NULL) {
rfile_name = argv[i];
} else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", record_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
break;
default:
if (rfile_name == NULL)
rfile_name = argv[i];
else {
Tcl_AppendResult(interp, "bad option: ",
"should be \"", record_usage, "\"",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
}
}
if (rfile_name == NULL) {
Tcl_AppendResult(interp, "Must specify rfile", (char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
} else {
if ((result = Tclm_GetMFile(interp, rfile_name, &rfile))
!= TCL_OK) {
if (tracks != NULL)
free(tracks);
return (result);
}
}
if (pfile_name == NULL)
play_tracks = NULL;
else {
if ((result = Tclm_GetMFile(interp, pfile_name, &pfile)) !=
TCL_OK) {
if (tracks != NULL)
free(tracks);
return (result);
}
play_tracks = pfile->tchunks;
}
/* If track list isn't set use all tracks */
if (pfile != NULL && num_tracks == 0) {
num_tracks = pfile->hchunk.num_trks;
if ((tracks = (int *)malloc(sizeof(int) * num_tracks))
== NULL) {
Tcl_AppendResult(interp, "Not enough memory",
(char *)NULL);
return (TCL_ERROR);
}
for (i = 0; i < num_tracks; i++)
tracks[i] = i;
}
if (pfile != NULL)
Mode = PLAYRECORD;
else {
num_tracks = 0;
Mode = RECORD;
}
if ((Dev = open_midi_device(Mode)) == -1) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
if (!init_midi_device(Dev, &rfile->hchunk, reltempo)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
if (!start_midi_device(Dev, Mode)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
if (!background) {
now_playing = 1;
if (!record_tracks(Dev, play_tracks, tracks, num_tracks,
&rfile->tchunks[0], repeat)) {
Tcl_AppendResult(interp, "Couldn't record track\n",
MidiError, (char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
now_playing = 0;
if (!stop_midi_device(Dev, Mode)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
/*
* give time for the stop to take effect
* since stop might not happen until next clock
*/
sleep(1);
if (!close_midi_device(Dev)) {
Tcl_AppendResult(interp, MidiError, (char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
Tcl_AppendResult(interp, "0", (char *)NULL);
} else {
if (pipe(Pipe) == -1) {
Tcl_AppendResult(interp, "Couldn't open pipe: ",
sys_errlist[errno]);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
switch(pid = fork()) {
case -1:
Tcl_AppendResult(interp, "Couldn't fork",
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
case 0:
/* child */
close(Pipe[0]);
now_playing = 1;
if (!record_tracks(Dev, play_tracks, tracks,
num_tracks, &rfile->tchunks[0], repeat))
exit(1);
now_playing = 0;
if (!stop_midi_device(Dev, Mode))
exit(1);
/*
* give time for the stop to take effect
* since stop might not happen until next clock
*/
sleep(1);
if (!close_midi_device(Dev))
exit(1);
/*
* write new track back to parent
*/
if (mwrite(Pipe[1], (char *)&rfile->tchunks[0].length,
sizeof(rfile->tchunks[0].length)) !=
sizeof(rfile->tchunks[0].length))
exit(1);
if (mwrite(Pipe[1],
(char *)rfile->tchunks[0].event_start,
rfile->tchunks[0].length) !=
rfile->tchunks[0].length)
exit(1);
close(Pipe[1]);
free(tmp_track);
exit(0);
default:
close(Pipe[1]);
if (!close_midi_device(Dev)) {
Tcl_AppendResult(interp, MidiError,
(char *)NULL);
if (tracks != NULL)
free(tracks);
return (TCL_ERROR);
}
sprintf(interp->result, "%d", pid);
break;
}
}
if (tracks != NULL)
free(tracks);
return (TCL_OK);
}
void
watchdog()
{
#ifdef UNION_WAIT
union wait wstatus;
#else
int wstatus;
#endif
(void)wait(&wstatus);
}
int
Tclm_ParseTracks(interp, list, tracks)
Tcl_Interp *interp;
char *list;
int **tracks;
{
char **track_strs;
char *chk_ptr;
int i;
int num_tracks;
if (Tcl_SplitList(interp, list, &num_tracks, &track_strs) != TCL_OK) {
Tcl_AppendResult(interp, "Bad track list", (char *)NULL);
return (-1);
}
if ((*tracks = (int *)malloc(sizeof(int) * num_tracks)) == NULL) {
Tcl_AppendResult(interp, "No more memory", (char *)NULL);
return (-1);
}
for (i = 0; i < num_tracks; i++) {
(*tracks)[i] = (int)strtol(track_strs[i], &chk_ptr, 0);
if (chk_ptr == track_strs[i]) {
Tcl_AppendResult(interp, "Bad track value ",
track_strs[i], (char *)NULL);
free(*tracks);
return (-1);
}
}
free((char *)track_strs);
return (num_tracks);
}
int
Tclm_MidiStop(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
MIDI_FILE *rfile;
char *chk_ptr;
unsigned char *events;
long length;
int pid;
int result;
/*
* argv[0] - midistop
* argv[1] - pid
* argv[2] - [rfile]
*/
if (argc < 2 || argc > 3) {
Tcl_AppendResult(interp, "wrong # args: should be\"",
argv[0], " pid [rfile]\"", (char *)NULL);
return (TCL_ERROR);
}
pid = (int)strtol(argv[1], &chk_ptr, 0);
if (chk_ptr == argv[1] || pid <= 0) {
Tcl_AppendResult(interp, "bad pid value: ", argv[1],
(char *)NULL);
return (TCL_ERROR);
}
if (kill(pid, SIGHUP) != -1)
Tcl_AppendResult(interp, "1", (char *)NULL);
else {
if (errno == ESRCH)
Tcl_AppendResult(interp, "0", (char *)NULL);
else {
Tcl_AppendResult(interp, "Error killing process: ",
sys_errlist[errno], (char *)NULL);
return (TCL_ERROR);
}
}
/* pick up recorded file if specified */
if (argc == 3) {
if ((result = Tclm_GetMFile(interp, argv[2], &rfile))
!= TCL_OK)
return (result);
if (mread(Pipe[0], (char *)&length, sizeof(length)) !=
sizeof(length)) {
Tcl_AppendResult(interp, "Couldn't read rfile: ",
sys_errlist[errno]);
close(Pipe[0]);
return (TCL_ERROR);
}
if ((events = (unsigned char *) malloc(length)) == NULL) {
Tcl_AppendResult(interp, "Not enough memory ",
"for record file", (char *)NULL);
close(Pipe[0]);
return (TCL_ERROR);
}
if (mread(Pipe[0], (char *)events, length) != length) {
Tcl_AppendResult(interp, "Couldn't read record ",
"track: ", sys_errlist[errno], (char *)NULL);
close(Pipe[0]);
free(events);
return (TCL_ERROR);
}
if (!put_smf_event(&rfile->tchunks[0], events, length)) {
Tcl_AppendResult(interp, "Couldn't add to ",
"record track: ", MidiError, (char *)NULL);
close(Pipe[0]);
free(events);
return (TCL_ERROR);
}
free(events);
close(Pipe[0]);
}
return (TCL_OK);
}
void
Tclm_CatchStop()
{
int ret;
ret = stop_processing(Dev);
}
#endif